Architettura delle Progressive Web App: Pattern per i Service Worker JavaScript | MLOG | MLOG

4. Network-Only

La strategia network-only recupera sempre le risorse dalla rete, bypassando completamente la cache. Questa strategia viene utilizzata quando si ha assolutamente bisogno della versione più recente di una risorsa e il caching non è desiderato.

Esempio:

            
self.addEventListener('fetch', event => {
  event.respondWith(
    fetch(event.request)
  );
});

            

5. Stale-While-Revalidate

La strategia stale-while-revalidate serve immediatamente la risorsa in cache mentre contemporaneamente recupera la versione più recente dalla rete. Una volta completata la richiesta di rete, la cache viene aggiornata con la nuova versione. Questa strategia fornisce una risposta iniziale veloce, garantendo al contempo che l'utente riceva alla fine il contenuto più aggiornato. È una strategia utile per contenuti non critici che beneficiano della velocità rispetto alla freschezza assoluta.

Esempio:

            
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        const fetchPromise = fetch(event.request).then(networkResponse => {
          caches.open('my-cache').then(cache => {
            cache.put(event.request, networkResponse.clone());
            return networkResponse;
          });
        });
        return response || fetchPromise;
      })
  );
});

            

6. Cache, poi Rete

Simile a stale-while-revalidate ma senza la restituzione immediata della risorsa in cache. Controlla prima la cache e solo se la risorsa è presente la richiesta di rete procederà in background per aggiornare la cache.

Scegliere la Giusta Strategia di Caching

La strategia di caching ottimale dipende dai requisiti specifici della tua applicazione. Considera fattori come:

Selezionando attentamente le strategie di caching appropriate, puoi migliorare significativamente le prestazioni e l'esperienza utente della tua PWA, anche in ambienti offline. Strumenti come Workbox ([https://developers.google.com/web/tools/workbox](https://developers.google.com/web/tools/workbox)) possono semplificare l'implementazione di queste strategie.

Sincronizzazione in Background: Gestire le Modifiche Offline

La sincronizzazione in background consente alla tua PWA di eseguire attività in background, anche quando l'utente è offline. Ciò è particolarmente utile per gestire l'invio di moduli, gli aggiornamenti dei dati e altre operazioni che richiedono connettività di rete. L'API `BackgroundSyncManager` ti consente di registrare attività che verranno eseguite quando la rete diventa disponibile.

Registrare un'Attività di Sincronizzazione in Background

Per registrare un'attività di sincronizzazione in background, devi utilizzare il metodo `register` del `BackgroundSyncManager`. Questo metodo accetta come argomento un nome di tag univoco. Il nome del tag identifica l'attività specifica da eseguire.

Esempio:

            
self.addEventListener('sync', event => {
  if (event.tag === 'my-sync-task') {
    event.waitUntil(doSomeWork());
  }
});

            

Gestire l'Evento di Sincronizzazione

Quando il browser rileva la connettività di rete, invia un evento `sync` al service worker. Puoi ascoltare questo evento ed eseguire le azioni necessarie, come l'invio di dati al server.

Esempio:

            
async function doSomeWork() {
  // Recupera i dati da IndexedDB
  const data = await getDataFromIndexedDB();

  // Invia i dati al server
  try {
    const response = await fetch('/api/sync', {
      method: 'POST',
      body: JSON.stringify(data),
      headers: {
        'Content-Type': 'application/json'
      }
    });

    if (response.ok) {
      // Cancella i dati da IndexedDB
      await clearDataFromIndexedDB();
    } else {
      // Gestisce gli errori
      console.error('Sincronizzazione fallita:', response.status);
      throw new Error('Sincronizzazione fallita');
    }
  } catch (error) {
    // Gestisce gli errori di rete
    console.error('Errore di rete:', error);
    throw error;
  }
}

            

Esempio: Invio di Moduli Offline

Immagina uno scenario in cui un utente compila un modulo mentre è offline. Il service worker può memorizzare i dati del modulo in IndexedDB e registrare un'attività di sincronizzazione in background. Quando la rete diventa disponibile, il service worker recupererà i dati del modulo da IndexedDB e li invierà al server.

  1. L'utente compila il modulo e clicca invia mentre è offline.
  2. I dati del modulo vengono memorizzati in IndexedDB.
  3. Viene registrata un'attività di sincronizzazione in background con un tag univoco (ad es. `form-submission`).
  4. Quando la rete è disponibile, viene attivato l'evento `sync`.
  5. Il service worker recupera i dati del modulo da IndexedDB e li invia al server.
  6. Se l'invio ha successo, i dati del modulo vengono rimossi da IndexedDB.

Notifiche Push: Coinvolgere gli Utenti con Aggiornamenti Tempestivi

Le notifiche push consentono alla tua PWA di inviare aggiornamenti e messaggi tempestivi agli utenti, anche quando l'app non è attivamente in esecuzione nel browser. Ciò può migliorare significativamente il coinvolgimento e la fidelizzazione degli utenti. L'API Push e l'API Notifications lavorano insieme per fornire le notifiche push.

Sottoscrivere le Notifiche Push

Per ricevere notifiche push, gli utenti devono prima concedere l'autorizzazione alla tua PWA. Puoi utilizzare l'API `PushManager` per sottoscrivere gli utenti alle notifiche push.

Esempio:

            
navigator.serviceWorker.ready.then(registration => {
  registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: 'YOUR_PUBLIC_VAPID_KEY'
  })
  .then(subscription => {
    // Invia i dettagli della sottoscrizione al tuo server
    sendSubscriptionToServer(subscription);
  })
  .catch(error => {
    console.error('Sottoscrizione fallita:', error);
  });
});

            

Importante: Sostituisci `YOUR_PUBLIC_VAPID_KEY` con la tua chiave VAPID (Voluntary Application Server Identification) pubblica effettiva. Le chiavi VAPID vengono utilizzate per identificare il tuo server applicativo e garantire che le notifiche push vengano inviate in modo sicuro.

Gestire le Notifiche Push

Quando viene ricevuta una notifica push, il service worker invia un evento `push`. Puoi ascoltare questo evento e mostrare la notifica all'utente.

Esempio:

            
self.addEventListener('push', event => {
  const payload = event.data ? event.data.text() : 'Nessun payload';

  event.waitUntil(
    self.registration.showNotification('My PWA', {
      body: payload,
      icon: 'icon.png'
    })
  );
});

            

Personalizzare le Notifiche Push

L'API Notifications ti consente di personalizzare l'aspetto e il comportamento delle notifiche push. Puoi specificare il titolo, il corpo, l'icona, il badge e altre opzioni.

Esempio:

            
self.addEventListener('push', event => {
  const data = event.data.json();
  const title = data.title || 'My PWA';
  const options = {
    body: data.body || 'Nessun messaggio',
    icon: data.icon || 'icon.png',
    badge: data.badge || 'badge.png',
    vibrate: [200, 100, 200],
    data: { // Dati personalizzati a cui puoi accedere quando l'utente clicca sulla notifica
      url: data.url || '/'
    },
    actions: [
      {action: 'explore', title: 'Esplora questo nuovo mondo',
        icon: 'images/checkmark.png'},
      {action: 'close', title: 'Chiudi',
        icon: 'images/xmark.png'},
    ]
  };

  event.waitUntil(self.registration.showNotification(title, options));
});


self.addEventListener('notificationclick', function(event) {
  event.notification.close();

  // Controlla se l'utente ha cliccato su un'azione.
  if (event.action === 'explore') {
    clients.openWindow(event.notification.data.url);
  } else {
    // Azione predefinita: apri l'app.
    clients.openWindow('/');
  }
});

            

Esempio: Allerta Notizie

Un'applicazione di notizie può utilizzare le notifiche push per avvisare gli utenti di notizie dell'ultima ora. Quando viene pubblicato un nuovo articolo, il server invia una notifica push al dispositivo dell'utente, mostrando un breve riassunto dell'articolo. L'utente può quindi cliccare sulla notifica per aprire l'articolo completo nella PWA.

Pattern Avanzati per i Service Worker

1. Analisi Offline

Traccia il comportamento degli utenti anche quando sono offline memorizzando i dati di analisi localmente e inviandoli al server quando la rete è disponibile. Ciò può essere ottenuto utilizzando IndexedDB e la Sincronizzazione in Background.

2. Versioning e Aggiornamento

Implementa una solida strategia di versioning per il tuo service worker per garantire che gli utenti ricevano sempre gli ultimi aggiornamenti senza interrompere la loro esperienza. Utilizza tecniche di cache busting per invalidare le vecchie risorse in cache.

3. Service Worker Modulari

Organizza il codice del tuo service worker in moduli per migliorare la manutenibilità e la leggibilità. Usa i moduli JavaScript (ESM) o un module bundler come Webpack o Rollup.

4. Caching Dinamico

Metti in cache le risorse dinamicamente in base alle interazioni dell'utente e ai modelli di utilizzo. Questo può aiutare a ottimizzare le dimensioni della cache e a migliorare le prestazioni.

Best Practice per lo Sviluppo di Service Worker

Conclusione

I service worker JavaScript sono strumenti potenti per costruire PWA robuste, performanti e coinvolgenti. Comprendendo il ciclo di vita del service worker e implementando strategie di caching appropriate, sincronizzazione in background e notifiche push, puoi creare esperienze utente eccezionali, anche in ambienti offline. Questo articolo ha esplorato i pattern chiave dei service worker e le best practice per guidarti nella costruzione di PWA di successo per un pubblico globale. Man mano che il web continua a evolversi, i service worker giocheranno un ruolo sempre più importante nel plasmare il futuro dello sviluppo web.

Ricorda di adattare questi pattern ai requisiti specifici della tua applicazione e di dare sempre la priorità all'esperienza utente. Abbracciando la potenza dei service worker, puoi creare PWA che non sono solo funzionali ma anche piacevoli da usare, indipendentemente dalla posizione o dalla connessione di rete dell'utente.

Risorse Aggiuntive: